<?php
// +----------------------------------------------------------------------------
// | Tke团队版权所属 [三十年河东三十年河西,莫欺少年穷.!]
// +----------------------------------------------------------------------------
// | Copyright (c) 2014 http://www.itdaodan.com All rights reserved.
// +----------------------------------------------------------------------------
// | Author: PHP@妖孽 <dino_ma@163.com>
// +----------------------------------------------------------------------------

namespace Admin\Model;
use Aliyun\OSS\OSSClient;
use Aliyun\OSS\Exceptions\OSSException;
use Aliyun\Common\Exceptions\ClientException;
/**
 * Oss处理模型
 */
class OssModel{
	
	private $aliyun;//阿里云操作句柄
	
	public $error;//记录最后一次错误信息
	/*
	 * <select class="form-control" name="Endpoint">
			<option value="http://oss-cn-qingdao.aliyuncs.com">青岛-外网</option>
			<option value="http://oss-cn-qingdao-internal.aliyuncs.com">青岛-内网</option>
			<option value="http://oss-cn-beijing.aliyuncs.com">北京-外网</option>
			<option value="http://oss-cn-beijing-internal.aliyuncs.com">北京-内网</option>
			<option value="http://oss-cn-hangzhou.aliyuncs.com">杭州-外网</option>
			<option value="http://oss-cn-hangzhou-internal.aliyuncs.com">杭州-内网</option>
			<option value="http://oss-cn-hongkong.aliyuncs.com">香港-外网</option>
			<option value="http://oss-cn-hongkong-internal.aliyuncs.com">香港-内网</option>
		</select>
	*/
	public $config=array(
			'Endpoint'=>'',
			'AccessKeyId'=>'',
			'AccessKeySecret'=>'',
			'bucket_name'=>''
	);
	
	function __construct(){
// 		session('aliyun', C('Alioss'));
		$this->config = array_merge($this->config, C('OSS_CONFIG'));
		$this->config['Endpoint']=C('OSS_POINT');
		import('Common.Api.aliyun');
		try {
			$this->aliyun = OSSClient::factory(array(
					'AccessKeyId' => $this->config['AccessKeyId'],
					'AccessKeySecret' => $this->config['AccessKeySecret'],
					'Endpoint' => $this->config['Endpoint'],
			));
		}catch (OSSException $ex) {
	        $this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
	        return false;
	    } catch (ClientException $ex) {
	       $this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
	       return false;
	    }
	}
	
   /**
    * @todo 获取bucket列表
    * @return array();
    */
	public function getBucketLists(){
		try {
			$array = $this->aliyun->listBuckets();
			if(empty($array)){
				return array();
			}else{
				$bucket_list = array();
				$acl_config = C('OSS_ACL_CONFIG');
				foreach ($array as $val){
					$info['name'] = $val->getName();
					$info['acl']  = $acl_config[$this->getBucketAcl($val->getName())];
					$date =  $val->getCreationDate()->getTimestamp();
					$info['creat_time'] =  $val->getCreationDate()->getTimestamp();
					array_push($bucket_list,$info);
					unset($info,$date);
				}
				return $bucket_list;
			}
		}catch (OSSException $ex) {
	        $this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
	        return false;
	    } catch (ClientException $ex) {
	       $this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
	       return false;
	    }
	}
	
	/**
	 * @todo 创建一个bucket
	 */
	public function addBucket(){
		$bucket = $this->checkBucket(false);
		if (!$bucket) {
			return false;
		}
		try {
			$is_add = $this->aliyun->createBucket(array(
					'Bucket' => $bucket
			));
			if($is_add){
				return true;
			}else{
				$this->error = '创建失败';
				return false;
			}
		}catch (OSSException $ex) {
	        $this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
	        return false;
	    } catch (ClientException $ex) {
	       $this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
	       return false;
	    }
	}
	
	/**
	 * @todo 干掉一个bucket
	 */
	public function delBucket(){
		$bucket = $this->checkBucket();
		if (!$bucket) {
			return false;
		}
		try{
			$is_del = $this->aliyun->deleteBucket(array(
		        'Bucket' => $bucket,
		    ));
			return true;
		}catch (OSSException $ex) {
	        $this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
	        return false;
	    } catch (ClientException $ex) {
	       $this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
	       return false;
	    }
	}
	/**
	 * @todo 检测bucket是否符合标准
	 * @param check_is_true true做校验,云端是否存在false在不做
	 * @return boolean|string
	 */
	public function checkBucket($check_is_true=true){
		$bucket = trim(I('bucket'));
		if($bucket ==''){
			$this->error='bucket不能为空';
			return false;
		}
		
		if(!preg_match('/^[a-zA-Z]+$/', $bucket)){
			$this->error='参数有误.~只允许输入英文.~';
			return false;
		}
		$len = strlen($bucket);
		if($len< 3 || $len >63){
			$this->error='bucket名称只支持3-63个英文字母';
			return false;
		}
		
		if($check_is_true){
			$bucket_list = $this->getBucketLists();
			if(!in_array($bucket, array_column($bucket_list, 'name'))){
				$this->error='bucket不存在请不要逗我~';
				return false;
			}
		}
		return $bucket;
	}
	
	/**
	 * @todo 获取某一个bucket权限信息
	 */
	public function getBucketAcl($bucket){
		if ($bucket =='') {
			$this->error = 'bucket参数不能为空';
			return false;
		}
		try{
			$bucket_acl = $this->aliyun->getBucketAcl(array(
		        'Bucket' => $bucket,
		    ));
			$grants = $bucket_acl->getGrants();
			if(empty($grants)){
				return '';
			}else{
				return $grants['0'];
			}
		}catch (OSSException $ex) {
	        $this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
	        return false;
	    } catch (ClientException $ex) {
	       $this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
	       return false;
	    }
	}
	
	/**
	 * @todo 为某一个bucket设置权限
	 */
	public function setBucketAcl($option=array()){
		if(empty($option)){
			$this->error = '参数不能为空';
			return false;
		}
		if ($option['Bucket'] =='') {
			$this->error = 'bucket参数不能为空';
			return false;
		}
		if ($option['ACL'] =='') {
			$this->error = 'ACL参数不能为空';
			return false;
		}
		try{
			$bucket_acl = $this->aliyun->setBucketAcl($option);
			return true;
		}catch (OSSException $ex) {
			$this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
			return false;
		} catch (ClientException $ex) {
			$this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
			return false;
		}
	}
	
	/**
	 * @todo 获取bucket下的object列表
	 */
	public function getObjectListByBucket(){
		$bucket = $this->checkBucket();
		if(!$bucket){
			return false;
		}
		try{
			$prefix  = ossDecrypt(I('prefix',''));
			if($prefix !=''){
				$prefix = str_replace('!', '/', $prefix);
			}else{
				$prefix = '';
			}
			$next_marker =trim(I('next_marker',''));
			if($next_marker !=''){
				$option = array(
						'Bucket'=>$bucket,
						'MaxKeys'=>20,
						'Marker'=>$next_marker,
						'Prefix'=>$prefix,
						'Delimiter' => '/',
				);
			}else{
				$option = array(
								'Bucket'=>$bucket,
								'MaxKeys'=>20,
								'Prefix'=>$prefix,
								'Delimiter' => '/',
							);
			}
			$object_list = $this->aliyun->listObjects($option);
			if(empty($object_list)){
				return array();
			}else{
				$images = array();//bucket下的静态图片
				$files = array();//bucket下的静态文件
				$folder = array();//bucket下的文件夹
				$old_array = array();
				//获取all
				foreach ($object_list->getObjectSummarys() as $summary) {
					$old_array['objcet_key'] = $summary->getKey();
					$old_array['is_dir']	=	false;
					$type = $this::getExt($summary->getKey());
					$old_array['type']	=	$type;
					$old_array['last_modify_time'] = $summary->getLastModified()->getTimestamp();
					$old_array['size'] = format_bytes($summary->getSize());
					$old_array['url'] = 'http://'.$bucket.'.oss-cn-hangzhou.aliyuncs.com/'.$summary->getKey();
					//获取存储类型
// 					$old_array['a'] = $summary->getStorageClass();
					if(in_array($type,C('IMG_EXT'))){
						array_push($images, $old_array);
					}else{
						array_push($files, $old_array);
					}
					unset($old_array);
				}
				//<li>is_truncated(bool,必选)-是否还有后续内容<li>
				//<li>	(string,可选)-下次请求的标志位<li>
				$return_array = array('is_truncated'=>$object_list->getIsTruncated(),'next_marker'=>$object_list->getNextMarker());
				//获取文件夹
				foreach($object_list->getCommonPrefixes() as $prefixes){
					$folder_array['prefix']= $prefixes;
					$folder_array['is_dir']= true;
					$folder_array['type']	=	'文件夹';
					$folder_array['last_modify_time'] = '-';
					$folder_array['size'] = '-';
					array_push($folder, $folder_array);
					unset($folder_array);
				}
				$return_array['list'] = array_merge($images,$folder,$files);
				return $return_array;
			}
		}catch (OSSException $ex) {
			$this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
			return false;
		} catch (ClientException $ex) {
			$this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
			return false;
		}
	}
	
	/**
	 * @todo 处理Object_key处理成path,name返回一个数组
	 * @param string $object_key OSS的$object_key
	 * @return array $return_array 包含以下参数
	 * <li>object_key(string, 必选) - object_key</li>
	 * <li>name(string, 必选) - 静态资源名称</li>
	 * <li>
	 * 	path(array, 必选) - 静态资源的路径
	 * 	<li>以0为索引的数组,为目录层次</li>
	 * </li>
	 */
	private static function handelObjectObjectKey($object_key){
		$return_array = array();
		if($object_key==''){
			$return_array['object_key'] = '';
			$return_array['name'] = '';
			$return_array['path'] = array();
			return $return_array;
		}
		$object_info = str2arr($object_key, '/');
		$sum = count($object_info);
		switch ($sum){
			//验证非空已经过滤$sum==0 的情况.所以在此步不在进行验证.
			case 1:
				//当sum等于1的时候,说名切割成数组后只有一个元素,则不存在目录的概念.~
				$return_array['object_key'] = $object_key;
				$return_array['name'] = $object_info['0'];
				$return_array['path'] = array();
				return $return_array;
				break;
			default:
				//判断是否是oss的协议来获取文件,如果在文件名后没有/跟参则为静态资源最终路径.
				if(strstr($object_info[($sum-1)], '.')){
					$return_array['name'] = $object_info[count($object_info)-1];
					//排除文件名来拼接路径
					array_pop($object_info);
					$return_array['path'] = $object_info;
					$return_array['object_key'] = $object_key;
					return $return_array;
				}else{
					//此逻辑为排除路径后跟的参数,获取路径和文件名
					//排除最后一个元素来拼接路径
					array_pop($object_info);
					$return_array['name'] = $object_info[count($object_info)-1];
					//排除文件名来拼接路径
					array_pop($object_info);
					$return_array['path'] = $object_info;
					$return_array['object_key'] = $object_key;
					return $return_array;
				}
				break;
		}
	}
	
	/**
	 * @todo  获取阿里OSS文件后缀名
	 */
	private static  function getExt($string){
		//     	$string = '140909/QFK0PL1L/300500.jpeg';
		// 		$string = '140909/140909/2TC4MOTP.jpeg/300500';
		// 		$string = '140909/2TC4MOTP.jpeg/300500';
		// 		$string = 'C1T6TTD9.jpeg';	
		// 		$string = '140909/QFK0PL1L/300500.jpeg/';
		if($string ==''){
			return false;
		}
		//		$string = '2014/20/';
		if(!strstr($string,'.')){
			return '-';
		}
		$object_info = str2arr($string, '/');
		$sum = count($object_info);
		if(!strstr($object_info[($sum-1)], '.')){
			array_pop($object_info);
		}
		$path_info = str2arr($object_info[count($object_info)-1], '.');
		return strtolower($path_info[(count($path_info)-1)]);
	}
	
	/**
	 * @todo 删除object
	 */
	public function deleteObject(){
		$bucket = $this->checkBucket();
		if(!$bucket){
			$this->error = 'bucket参数有误';
			return false;
		}
		$key = trim(I('key'));
		if($key==''){
			$this->error = 'key不能为空';
			return false;
		}
		
		try{
			$bucket_acl = $this->aliyun->deleteObject(array(
		        'Bucket' => $bucket,
		        'Key' => $key,
		    ));
			return true;
		}catch (OSSException $ex) {
			$this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
			return false;
		} catch (ClientException $ex) {
			$this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
			return false;
		}
	}
	
	/**
	 * @todo 创建文件夹
	 */
	public function creatDir(){
		$bucket = $this->checkBucket();
		if(!$bucket){
			$this->error = 'bucket参数有误';
			return false;
		}
		$key = trim(I('key'));
		if($key==''){
			$this->error = 'key不能为空';
			return false;
		}
		$prefix  = ossDecrypt(I('prefix',''));
		if($prefix !=''){
			$prefix = str_replace('!', '/', $prefix);
		}else{
			$prefix = '';
		}
		try{
			$bucket_acl = $this->aliyun->putObject(array(
			    'Bucket' => $bucket,
				'Key' => $prefix.$key,
			    'Content' =>'',
			    'ContentLength' => 0,
			));
			return true;
		}catch (OSSException $ex) {
			$this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
			return false;
		} catch (ClientException $ex) {
			$this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
			return false;
		}
	}
	
	
	/**
	 * @todo 上传文件
	 * 考虑到以后阿里云有可能把文件夹跟文件的创建拆分开所以写了两个方法.~
	 */
	public function creatFile(){
		$bucket = $this->checkBucket();
		if(!$bucket){
			$this->error = 'bucket参数有误';
			return false;
		}
		
		$prefix  = ossDecrypt(I('prefix',''));
		if($prefix !=''){
			$prefix = str_replace('!', '/', $prefix);
		}else{
			$prefix = '';
		}
		try{
			$file_name = $prefix.date('Y/m/d-H-i').'/'.uniqid().'.'.$this->getExt($_FILES['file']['name']);
			$option = array(
					'Bucket' => $bucket,
					'Key' => $file_name,
					'Content' =>fopen($_FILES["file"]["tmp_name"], "r"),
					'ContentLength' =>$_FILES['file']['size'],
					'ContentType'=>$_FILES['file']['type'],
			);
			$bucket_acl = $this->aliyun->putObject($option);
			return $file_name;
		}catch (OSSException $ex) {
			$this->error= "OSSException: " . $ex->getErrorCode() . " Message: " . $ex->getMessage();
			return false;
		} catch (ClientException $ex) {
			$this->error=  "ClientExcetpion, Message: " . $ex->getMessage();
			return false;
		}
	}
	
	/**
	 * @todo 返回最后一次错误信息
	 * @return string
	 */
	public function getError(){
		return $this->error;
	}
	
	
}
